using System;
using NUnit.Framework;
using System.Text;
using System.IO;
using System.Collections.Generic;

namespace ProgrammingLanguageNr1
{
	[TestFixture()]
	public class Parser_TEST
	{
		static ErrorHandler s_errorHandler = new ErrorHandler();
		
		[Test()]
		public void ParseCode1 ()
		{
			Tokenizer tokenizer = new Tokenizer(File.OpenText("code1.txt"), s_errorHandler);
			List<Token> tokens = tokenizer.getTokens();
			Parser parser = new Parser(tokens, s_errorHandler);
			parser.process();
		}
		
		[Test()]
		public void ParseCode2 ()
		{
			Tokenizer tokenizer = new Tokenizer(File.OpenText("code2.txt"), s_errorHandler);
			List<Token> tokens = tokenizer.getTokens();
			Parser parser = new Parser(tokens, s_errorHandler);
			parser.process();
		}
		
		[Test()]
		public void ParseCode3 ()
		{
			Tokenizer tokenizer = new Tokenizer(File.OpenText("code3.txt"), s_errorHandler);
			List<Token> tokens = tokenizer.getTokens();
			Parser parser = new Parser(tokens, s_errorHandler);
			parser.process();
		}
		
		[Test()]
		public void Lookahead ()
		{
			List<Token> tokens = new List<Token>();
			tokens.Add(new Token(Token.TokenType.NAME, "a"));
			tokens.Add(new Token(Token.TokenType.NUMBER, "45"));
			tokens.Add(new Token(Token.TokenType.OPERATOR, "+"));
			tokens.Add(new Token(Token.TokenType.NEW_LINE, "<NEW_LINE>"));
			tokens.Add(new Token(Token.TokenType.EOF, "<EOF>"));
			
			Parser parser = new Parser(tokens, s_errorHandler);
			Assert.AreEqual(Token.TokenType.NAME,     parser.lookAhead(1).getTokenType());
			Assert.AreEqual(Token.TokenType.NUMBER,   parser.lookAhead(2).getTokenType());
			Assert.AreEqual(Token.TokenType.OPERATOR, parser.lookAhead(3).getTokenType());
			
			parser.consumeCurrentToken();
			parser.consumeCurrentToken();
			
			Assert.AreEqual(Token.TokenType.OPERATOR, parser.lookAheadType(1));
			Assert.AreEqual(Token.TokenType.NEW_LINE, parser.lookAheadType(2));
			Assert.AreEqual(Token.TokenType.EOF, 	  parser.lookAheadType(3));
			
			parser.consumeCurrentToken();
			parser.consumeCurrentToken();
			
			Assert.AreEqual(Token.TokenType.EOF, 	  parser.lookAhead(1).getTokenType());
		}
		
		[Test()]
		public void ParseSimpleExpression ()
		{
			List<Token> tokens = new List<Token>();
			tokens.Add(new Token(Token.TokenType.NAME, "a"));
			tokens.Add(new Token(Token.TokenType.OPERATOR, "+"));
			tokens.Add(new Token(Token.TokenType.NAME, "b"));
		
			ErrorHandler errorHandler = new ErrorHandler();
			Parser parser = new Parser(tokens, errorHandler);
			parser.process();
			
			Assert.AreEqual(0, errorHandler.getErrors().Count);
		}
		
		[Test()]
		public void ParseAssignment ()
		{
			List<Token> tokens = new List<Token>();
			tokens.Add(new Token(Token.TokenType.NAME, "variable"));
			tokens.Add(new Token(Token.TokenType.ASSIGNMENT, "="));
			tokens.Add(new Token(Token.TokenType.NUMBER, "42"));
			
			ErrorHandler errorHandler = new ErrorHandler();
			Parser parser = new Parser(tokens, errorHandler);
			parser.process();
			
			Assert.AreEqual(0, errorHandler.getErrors().Count);
		}
		
		[Test()]
		public void ParseSingleName ()
		{
			List<Token> tokens = new List<Token>();
			tokens.Add(new Token(Token.TokenType.NAME, "erik"));
			
			ErrorHandler errorHandler = new ErrorHandler();
			Parser parser = new Parser(tokens, errorHandler);
			parser.process();
			
			Assert.AreEqual(0, errorHandler.getErrors().Count);
		}
		
		[Test()]
		public void ParseLongerExpression ()
		{
			List<Token> tokens = new List<Token>();
			
			tokens.Add(new Token(Token.TokenType.NUMBER, "2"));
			tokens.Add(new Token(Token.TokenType.OPERATOR, "*"));
			tokens.Add(new Token(Token.TokenType.NUMBER, "3"));
			tokens.Add(new Token(Token.TokenType.OPERATOR, "+"));
			tokens.Add(new Token(Token.TokenType.NUMBER, "4"));
			tokens.Add(new Token(Token.TokenType.OPERATOR, "*"));
			tokens.Add(new Token(Token.TokenType.NUMBER, "5"));
			
			ErrorHandler errorHandler = new ErrorHandler();
			Parser parser = new Parser(tokens, errorHandler);
			parser.process();
			
			Assert.AreEqual(0, errorHandler.getErrors().Count);
		}
		
		[Test()]
		public void ParseFunctionCallWithParameters ()
		{
			List<Token> tokens = new List<Token>();
			
			tokens.Add(new Token(Token.TokenType.NAME, "foo"));
			tokens.Add(new Token(Token.TokenType.PARANTHESIS_LEFT, "("));
			tokens.Add(new Token(Token.TokenType.NAME, "a"));
			tokens.Add(new Token(Token.TokenType.COMMA, ","));
			tokens.Add(new Token(Token.TokenType.NAME, "bar"));
			tokens.Add(new Token(Token.TokenType.PARANTHESIS_LEFT, "("));
			tokens.Add(new Token(Token.TokenType.PARANTHESIS_RIGHT, ")"));
			tokens.Add(new Token(Token.TokenType.COMMA, ","));
			tokens.Add(new Token(Token.TokenType.NUMBER, "400"));
			tokens.Add(new Token(Token.TokenType.PARANTHESIS_RIGHT, ")"));
			
			ErrorHandler errorHandler = new ErrorHandler();
			Parser parser = new Parser(tokens, errorHandler);
			parser.process();
			
			Assert.AreEqual(0, errorHandler.getErrors().Count);
		}
		
		[Test()]
		public void ParseIfElseBlock ()
		{
			List<Token> tokens = new List<Token>();
			
			tokens.Add(new Token(Token.TokenType.IF, "if"));
			tokens.Add(new Token(Token.TokenType.PARANTHESIS_LEFT, "("));
			tokens.Add(new Token(Token.TokenType.NAME, "m_hasGotCandy"));
			tokens.Add(new Token(Token.TokenType.PARANTHESIS_RIGHT, ")"));
			tokens.Add(new Token(Token.TokenType.BLOCK_BEGIN, "{"));
			tokens.Add(new Token(Token.TokenType.NAME, "boringFunction"));
			tokens.Add(new Token(Token.TokenType.PARANTHESIS_LEFT, "("));
			tokens.Add(new Token(Token.TokenType.PARANTHESIS_RIGHT, ")"));
			tokens.Add(new Token(Token.TokenType.NEW_LINE, "\n"));
			tokens.Add(new Token(Token.TokenType.BLOCK_END, "}"));
			tokens.Add(new Token(Token.TokenType.ELSE, "else"));
			tokens.Add(new Token(Token.TokenType.BLOCK_BEGIN, "{"));
			tokens.Add(new Token(Token.TokenType.BLOCK_END, "}"));
			
			ErrorHandler errorHandler = new ErrorHandler();
			Parser parser = new Parser(tokens, errorHandler);
			parser.process();
			
			Assert.AreEqual(0, errorHandler.getErrors().Count);
		}
		
		[Test()]
		public void ParseFunctionDeclaration ()
		{
			List<Token> tokens = new List<Token>();
			
			tokens.Add(new Token(Token.TokenType.NAME, "int"));
			tokens.Add(new Token(Token.TokenType.NAME, "foo"));
			tokens.Add(new Token(Token.TokenType.PARANTHESIS_LEFT, "("));
			tokens.Add(new Token(Token.TokenType.PARANTHESIS_RIGHT, ")"));
			tokens.Add(new Token(Token.TokenType.BLOCK_BEGIN, "{"));
			tokens.Add(new Token(Token.TokenType.BLOCK_END, "}"));
			
			ErrorHandler errorHandler = new ErrorHandler();
			Parser parser = new Parser(tokens, errorHandler);
			parser.process();
			
			//Console.WriteLine("Tree: " + parser.getAST().getTreeAsString());
			
			Assert.AreEqual(0, errorHandler.getErrors().Count);
		}
		
		[Test()]
		public void ParseSomeExpressionsWithFunctions ()
		{
			Tokenizer tokenizer = new Tokenizer(File.OpenText("code15.txt"), s_errorHandler);
			List<Token> tokens = tokenizer.getTokens();
			
			ErrorHandler errorHandler = new ErrorHandler();
			Parser parser = new Parser(tokens, errorHandler);
			parser.process();
			
			//Console.WriteLine("Tree: " + parser.getAST().getTreeAsString());
			
			Assert.AreEqual(0, errorHandler.getErrors().Count);
		}
	}
}

